
const { ccclass, property } = cc._decorator;

let sys = cc.sys
let _mat4_temp = cc.mat4();


export enum WebViewEventType {
    LOADING = 0,
    LOADED = 1,
    ERROR = 2,
    JS_EVALUATED = 3
}

@ccclass
export default class TrumpWebViewImpl {

    _EventList = {};

    _visible = false;
    _parent = null;
    _div = null;
    _iframe = null;
    _listener = null;
    _forceUpdate = false;


    // update matrix cache
    _m00 = 0;
    _m01 = 0;
    _m04 = 0;
    _m05 = 0;
    _m12 = 0;
    _m13 = 0;
    _w = 0;
    _h = 0;
    __eventListeners = {};

    ctor() {
        // this.setContentSize(cc.size(300, 200));
        this._EventList = {};

        this._visible = false;
        this._parent = null;
        this._div = null;
        this._iframe = null;
        this._listener = null;
        this._forceUpdate = false;

        // update matrix cache
        this._m00 = 0;
        this._m01 = 0;
        this._m04 = 0;
        this._m05 = 0;
        this._m12 = 0;
        this._m13 = 0;
        this._w = 0;
        this._h = 0;
        //
        this.__eventListeners = {};
    }

    _updateVisibility() {
        if (!this._div) return;
        let div = this._div;
        if (this._visible) {
            div.style.visibility = 'visible';
        }
        else {
            div.style.visibility = 'hidden';
        }
    }

    _updateSize(w, h) {
        let div = this._div;
        if (div) {
            div.style.width = cc.view.getFrameSize().width + "px";
            div.style.height = cc.view.getFrameSize().height + "px";
        }
    }

    _initEvent() {
        let iframe = this._iframe;
        if (iframe) {
            let cbs = this.__eventListeners, self = this;
            //@ts-ignore
            cbs.load = function () {
                self._forceUpdate = true;
                self._dispatchEvent(WebViewEventType.LOADED);
            };
            //@ts-ignore
            cbs.error = function () {
                self._dispatchEvent(WebViewEventType.ERROR);
            };
            //@ts-ignore
            iframe.addEventListener("load", cbs.load);
            //@ts-ignore
            iframe.addEventListener("error", cbs.error);
        }
    }

    _initStyle() {
        if (!this._div) return;
        let div = this._div;
        div.style.position = "absolute";
        div.style.bottom = "0px";
        div.style.left = "0px";
    }

    _setOpacity(opacity) {
        let iframe = this._iframe;
        if (iframe && iframe.style) {
            iframe.style.opacity = opacity / 255;
        }
    }

    _createDom(w, h) {
        //@ts-ignore
        if (TrumpWebViewImpl._polyfill.enableDiv) {
            this._div = document.createElement("div");
            this._div.style["-webkit-overflow"] = "auto";
            this._div.style["-webkit-overflow-scrolling"] = "touch";
            this._iframe = document.createElement("iframe");
            this._div.appendChild(this._iframe);
            this._iframe.style.width = "100%";
            this._iframe.style.height = "100%";
            // this._div.style["pointer-events"] = "none";

            // let div = document.createElement("div")
            // div.style.width = "100%"
            // div.style.height = "100%"
            // div.style.position = "absolute"
            // div.style.top = "0"
            // div.style.left = "0"
            // div.style.backgroundColor = "transparent"
            // div.style.pointerEvents = "none"
            // div.style.zIndex = "10"
            // this._div.appendChild(div)
        }
        else {
            this._div = this._iframe = document.createElement("iframe");
        }
        //@ts-ignore    
        if (TrumpWebViewImpl._polyfill.enableBG)
            this._div.style["background"] = "#FFF";

        this._div.style.height = h + "px";
        this._div.style.width = w + "px";
        // this._div.style.overflow = "scroll";
        this._iframe.style.border = "none";

        cc.game.container.appendChild(this._div);
        this._updateVisibility();
    }

    _createNativeControl(w, h) {
        this._createDom(w, h);
        this._initStyle();
        this._initEvent();
    }

    createDomElementIfNeeded = CC_EDITOR ? function (w, h) {
        this._div = document.createElement('div');
        this._div.style.background = 'rgba(255, 255, 255, 0.8)';
        this._div.style.color = 'rgb(51, 51, 51)';
        this._div.style.height = w + 'px';
        this._div.style.width = h + 'px';
        this._div.style.position = 'absolute';
        this._div.style.bottom = '0px';
        this._div.style.left = '0px';
        this._div.style['word-wrap'] = 'break-word';
        cc.game.container.appendChild(this._div);
    } : function (w, h) {
        if (!this._div) {
            this._createNativeControl(w, h);
        }
        else {
            this._updateSize(w, h);
        }
    }

    contains(refNode, otherNode) {
        if (typeof refNode.contains == 'function') {
            return refNode.contains(otherNode);
        } else if (typeof refNode.compareDocumentPosition == 'function') {
            return !!(refNode.compareDocumentPosition(otherNode) & 16);
        } else {
            var node = otherNode.parentNode;
            if (node) {
                do {
                    if (node === refNode) {
                        return true;
                    } else {
                        node = node.parentNode;
                    }
                } while (node !== null);
            }
            return false;
        }
    }

    removeDom() {
        let div = this._div;
        if (div) {
            let hasChild = this.contains(cc.game.container, div);
            if (hasChild)
                cc.game.container.removeChild(div);

            this._div = null;
        }
        let iframe = this._iframe;
        if (iframe) {
            let cbs = this.__eventListeners;
            //@ts-ignore
            iframe.removeEventListener("load", cbs.load);
            //@ts-ignore
            iframe.removeEventListener("error", cbs.error);
            //@ts-ignore
            cbs.load = null;
            //@ts-ignore
            cbs.error = null;
            this._iframe = null;
        }
    }

    setOnJSCallback(callback) { }
    setJavascriptInterfaceScheme(scheme) { }
    // private method
    loadData(data, MIMEType, encoding, baseURL) { }
    loadHTMLString(string, baseURL) { }

    /**
     * Load an URL
     * @param {String} url
     */
    loadURL = CC_EDITOR ? function (url) {
        this._div.innerText = url;
    } : function (url) {
        let iframe = this._iframe;
        if (iframe) {
            iframe.src = url;
            let self = this;
            let cb = function () {
                self._loaded = true;
                self._updateVisibility();
                iframe.removeEventListener("load", cb);
            };
            iframe.addEventListener("load", cb);
            this._dispatchEvent(WebViewEventType.LOADING);
        }
    }

    /**
     * Stop loading
     */
    stopLoading() {
    }

    /**
     * Reload the WebView
     */
    reload() {
        let iframe = this._iframe;
        if (iframe) {
            let win = iframe.contentWindow;
            if (win && win.location)
                win.location.reload();
        }
    }

    /**
     * Determine whether to go back
     */
    canGoBack() {
        return true;
    }

    /**
     * Determine whether to go forward
     */
    canGoForward() {
        return true;
    }

    /**
     * go back
     */
    goBack() {
        try {
            //@ts-ignore
            if (TrumpWebViewImpl._polyfill.closeHistory)
                return;
            let iframe = this._iframe;
            if (iframe) {
                let win = iframe.contentWindow;
                if (win && win.location)
                    win.history.back.call(win);
            }
        } catch (err) {
            cc.log(err);
        }
    }

    /**
     * go forward
     */
    goForward() {
        try {
            //@ts-ignore
            if (TrumpWebViewImpl._polyfill.closeHistory)
                return
            let iframe = this._iframe;
            if (iframe) {
                let win = iframe.contentWindow;
                if (win && win.location)
                    win.history.forward.call(win);
            }
        } catch (err) {
            cc.log(err);
        }
    }

    /**
     * In the webview execution within a period of js string
     * @param {String} str
     */
    evaluateJS(str) {
        let iframe = this._iframe;
        if (iframe) {
            let win = iframe.contentWindow;
            try {
                win.eval(str);
                this._dispatchEvent(WebViewEventType.JS_EVALUATED);
            } catch (err) {
                console.error(err);
            }
        }
    }

    /**
     * Limited scale
     */
    setScalesPageToFit() {
    }

    /**
     * The binding event
     * @param {WebViewImpl.EventType} event
     * @param {Function} callback
     */
    setEventListener(event, callback) {
        this._EventList[event] = callback;
    }

    /**
     * Delete events
     * @param {WebViewImpl.EventType} event
     */
    removeEventListener(event) {
        this._EventList[event] = null;
    }

    _dispatchEvent(event) {
        let callback = this._EventList[event];
        if (callback)
            callback.call(this, this, this._iframe.src);
    }

    _createRenderCmd() {
        //@ts-ignore
        return new TrumpWebViewImpl.RenderCmd(this);
    }

    destroy() {
        this.removeDom();
    }

    setVisible(visible) {
        if (this._visible !== visible) {
            this._visible = !!visible;
            this._updateVisibility();
        }
    }

    updateMatrix(node) {
        if (!this._div || !this._visible) return;

        node.getWorldMatrix(_mat4_temp);

        //@ts-ignore
        let renderCamera = cc.Camera._findRendererCamera(node);
        if (renderCamera) {
            renderCamera.worldMatrixToScreen(_mat4_temp, _mat4_temp, cc.game.canvas.width, cc.game.canvas.height);
        }

        let _mat4_tempm = _mat4_temp.m;
        if (!this._forceUpdate &&
            this._m00 === _mat4_tempm[0] && this._m01 === _mat4_tempm[1] &&
            this._m04 === _mat4_tempm[4] && this._m05 === _mat4_tempm[5] &&
            this._m12 === _mat4_tempm[12] && this._m13 === _mat4_tempm[13] &&
            this._w === node._contentSize.width && this._h === node._contentSize.height) {
            return;
        }

        // update matrix cache
        this._m00 = _mat4_tempm[0];
        this._m01 = _mat4_tempm[1];
        this._m04 = _mat4_tempm[4];
        this._m05 = _mat4_tempm[5];
        this._m12 = _mat4_tempm[12];
        this._m13 = _mat4_tempm[13];
        this._w = node._contentSize.width;
        this._h = node._contentSize.height;

        //@ts-ignore
        let dpr = cc.view._devicePixelRatio;
        let scaleX = 1 / dpr;
        let scaleY = 1 / dpr;

        let container = cc.game.container;
        let a = _mat4_tempm[0] * scaleX, b = _mat4_tempm[1], c = _mat4_tempm[4], d = _mat4_tempm[5] * scaleY;

        let offsetX = container && container.style.paddingLeft ? parseInt(container.style.paddingLeft) : 0;
        let offsetY = container && container.style.paddingBottom ? parseInt(container.style.paddingBottom) : 0;
        this._updateSize(this._w, this._h);
        let w = this._w * scaleX;
        let h = this._h * scaleY;

        let appx = (w * _mat4_tempm[0]) * node._anchorPoint.x;
        let appy = (h * _mat4_tempm[5]) * node._anchorPoint.y;


        let tx = _mat4_tempm[12] * scaleX - appx + offsetX, ty = _mat4_tempm[13] * scaleY - appy + offsetY;

        // let matrix = "matrix(" + a + "," + -b + "," + -c + "," + d + "," + tx + "," + -ty + ")";
        // this._div.style['transform'] = matrix;
        // this._div.style['-webkit-transform'] = matrix;
        this._div.style['transform-origin'] = '0px 100% 0px';
        this._div.style['-webkit-transform-origin'] = '0px 100% 0px';
        // this._div.style['id'] =

        // chagned iframe opacity
        this._setOpacity(node.opacity);
        this._forceUpdate = false;
    }
}

let polyfill = TrumpWebViewImpl['_polyfill'] = {
    devicePixelRatio: false,
    enableDiv: false
};

if (cc.sys.os === cc.sys.OS_IOS)
    polyfill.enableDiv = true;

if (sys.isMobile) {
    if (sys.browserType === sys.BROWSER_TYPE_FIREFOX) {
        polyfill['enableBG'] = true;
    }
}
else {
    if (sys.browserType === sys.BROWSER_TYPE_IE) {
        polyfill['closeHistory'] = true;
    }
}
